package com.koron.operation.census.services;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.koron.operation.census.bean.*;
import com.koron.operation.dispatch.bean.EquipmentBean;
import com.koron.operation.dispatch.bean.EquipmentHistoryBean;
import com.koron.operation.dispatch.bean.dto.EquipmentDto;
import com.koron.operation.dispatch.enums.EquipmentEnum;
import com.koron.operation.dispatch.enums.OverhaulStatusEnum;
import com.koron.operation.dispatch.mapper.EquipmentDeMapper;
import com.koron.operation.dispatch.mapper.EquipmentHistoryMapper;
import com.koron.operation.startlog.bean.StartLogBean;
import com.koron.operation.startlog.enums.StartLogEnum;
import com.koron.operation.startlog.mapper.StartLogBeanMapper;
import com.koron.operation.util.IntactRatioUntil;
import lombok.extern.slf4j.Slf4j;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: rocky
 * @Date: 2022/2/22 11:39
 */

@Slf4j
@Service
public class IntactRatioService {


    /**
     * 机组完好率详情
     *
     * @param factory
     * @param dto
     * @return
     */
    @TaskAnnotation("intactRatioDetails")
    public List<IntactRatioVo> intactRatioDetails(SessionFactory factory, IntactRatioDto dto) {

        EquipmentDeMapper mapper = factory.getMapper(EquipmentDeMapper.class);
        EquipmentHistoryMapper historymapper = factory.getMapper(EquipmentHistoryMapper.class);
        //指定年份机组全部记录
        List<EquipmentHistoryBean> unitAllRelist = historymapper.queryByEquipmentTypeAndYear(EquipmentEnum.UNIT.getValue(), dto.getYear());
        EquipmentDto equipmentDto = new EquipmentDto(EquipmentEnum.UNIT.getValue());
        //所有机组
        List<EquipmentBean> allUnitlist = mapper.queryList(equipmentDto);
        //所有单位
        Map<String, String> managemap = allUnitlist.stream().collect(Collectors.toMap(EquipmentBean::getDeptManage, EquipmentBean::getDeptManageName, (v1, v2) -> v1));
        List<String> managelist = allUnitlist.stream().map(EquipmentBean::getDeptManage).distinct().collect(Collectors.toList());
        //单位下机组数量
        Map<String, List<EquipmentBean>> mangeCountUnitmap = allUnitlist.stream().collect(Collectors.groupingBy(EquipmentBean::getDeptManage));
        //单位下机组记录
        Map<String, List<EquipmentHistoryBean>> mangeCountRemap = unitAllRelist.stream().collect(Collectors.groupingBy(EquipmentHistoryBean::getDeptManage));

        //所有部门
        List<String> depts = allUnitlist.stream().map(EquipmentBean::getDeptId).distinct().collect(Collectors.toList());
        Map<String, String> deptmap = allUnitlist.stream().collect(Collectors.toMap(EquipmentBean::getDeptId, EquipmentBean::getDeptName, (v1, v2) -> v2));
        //部门下的单位
        Map<String, List<String>> manageDept = new HashMap<>();
        for (String s : deptmap.keySet()) {
            List<String> manage = allUnitlist.stream().filter(u -> u.getDeptId().equals(s)).map(EquipmentBean::getDeptManage).distinct().collect(Collectors.toList());
            manageDept.put(s, manage);
        }

        //所有机组每月最新的一条记录
        List<Map<String, EquipmentHistoryBean>> yearRecordList = new ArrayList<>();
        for (int i = 1; i <= 12; i++) {
            Map<String, EquipmentHistoryBean> reMonthlast = new HashMap<>();
            if (i <= dto.getEndMonth() && i >= dto.getStartMonth()) {
                Calendar instance = Calendar.getInstance();
                instance.set(dto.getYear(), i-1,1);
                Date time = instance.getTime();
                DateTime dateTime = DateUtil.beginOfMonth(time);
                List<EquipmentHistoryBean> historyListDtos = historymapper.queryByYearAndMonthAndTypeLastRe(dateTime, EquipmentEnum.UNIT.getValue());
                for (EquipmentHistoryBean historyListDto : historyListDtos) {
                    reMonthlast.put(historyListDto.getEquipmentId(), historyListDto);
                }
            }
            yearRecordList.add(reMonthlast);
        }

        // 遍历单位
        List<IntactRatioVo> managevo = new ArrayList<>();
        for (String s : managelist) {
            IntactRatioVo vo = new IntactRatioVo();
            vo.setDeptId(s);
            vo.setDeptName(managemap.get(s));
            vo.setCount(mangeCountUnitmap.get(s).size());

            //计算月机组完好率指标项
            List<IntacQuotaDetVo> monthItems = new ArrayList<>();
            for (int j = 1; j < 13; j++) {
                String month = j + "";
                if (j < 10) {
                    month = "0" + month;
                }
                Date curMonth = DateUtil.parse(dto.getYear() + "-" + month + "-" + "01");
                //每个月有多少天
                int daysOfMonth = DateUtil.lengthOfMonth(j, DateUtil.isLeapYear(dto.getYear()));
                //每月每一天和最后一天 ， 用于统计每月检修台时
                Date startDate = DateUtil.beginOfMonth(curMonth);
                Date endDate = DateUtil.endOfMonth(curMonth);
                long l = endDate.getTime();
                endDate = DateUtil.date(l);
                //当前时间 如果大于 月结束时间 ，使用月结束时间
                Date curDate = new Date();
                if (curDate.getTime() - endDate.getTime() > 0) {
                    curDate = endDate;
                }

                IntacQuotaDetVo item = new IntacQuotaDetVo();
                //标准台时
                double standTimes = 0d;
                //总检修台时：数据來至各单位检修工单（检修工作总时间）
                double allProdTimes = 0d;
                //非故障检修台时：数据來至各单位非故障检修工单（非故障检修工作总时间）括大修、计划检修、正常维护
                double notProdTimes = 0d;

                if (j >= dto.getStartMonth() && j <= dto.getEndMonth()) {
                    if ((j - 1) <= Calendar.getInstance().get(Calendar.MONTH) || dto.getYear() < Calendar.getInstance().get(Calendar.YEAR)) {
                        standTimes = IntactRatioUntil.queryStandTimes(startDate, daysOfMonth, mangeCountUnitmap.get(s));
                        //单位下所有机组
                        List<EquipmentBean> unitlist = mangeCountUnitmap.get(s);
                        List<EquipmentHistoryBean> unitRecordList = getUniRecordList(startDate, endDate, mangeCountRemap.get(s));
                        Map<String, List<EquipmentHistoryBean>> eqidRemap = unitRecordList.stream().collect(Collectors.groupingBy(EquipmentHistoryBean::getEquipmentId));
                        for (EquipmentBean unit : unitlist) {
                            //单个单位一个月 机组的记录
                            Map<String, EquipmentHistoryBean> lastHistorymap = yearRecordList.get(j - 1);
                            EquipmentHistoryBean latelyRecord = lastHistorymap.get(unit.getEquipmentId());//机组相应月份的最后一条记录
                            allProdTimes += getUnitDisableTime("ALL", latelyRecord, curDate, startDate, endDate, eqidRemap.get(unit.getEquipmentId()));
                            notProdTimes += getUnitDisableTime("NOT", latelyRecord, curDate, startDate, endDate, eqidRemap.get(unit.getEquipmentId()));
                        }
                    }


                }

                item.setStandTimes(standTimes);
                item.setAllProdTimes(Math.round(allProdTimes * 100) / 100d);
                item.setNotProdTimes(Math.round(notProdTimes * 100) / 100d);
                //设备完好率：（标准台时-总检修台时）/（月标准台时-非故障检修台时）
                if (j >= dto.getStartMonth() && j <= dto.getEndMonth()) {
                    if (standTimes - notProdTimes == 0 || allProdTimes == 0d) {
                        int nowmonth = DateUtil.month(new Date()) + 1;
                        if (j <= nowmonth) {
                            item.setIntactRate(BigDecimal.valueOf(100l));
                        } else {
//                            item.setIntactRate(BigDecimal.ZERO);
                            // 如果完好率为0显示100%
                            item.setIntactRate(BigDecimal.valueOf(100));
                        }
                    } else {
                        Double intactRate = (standTimes - allProdTimes) / (standTimes - notProdTimes);
                        BigDecimal ratio = BigDecimal.valueOf(intactRate).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                        item.setIntactRate(ratio);
                    }

                }
                monthItems.add(item);
            }
            vo.setMonthItems(monthItems);//月度

            //统计季度
            List<IntacQuotaDetVo> quarterItems = new ArrayList<>();
            //统计上半年
            IntacQuotaDetVo halfYearItems = new IntacQuotaDetVo();
            //统计年
            IntacQuotaDetVo yearItems = new IntacQuotaDetVo();
            Double yearStanTimes = 0d;
            Double yearAllProdTimes = 0d;
            Double yearNotProdTimes = 0d;
            //半年
            Double halfYearStanTimes = 0d;
            Double halfYearAllProdTimes = 0d;
            Double halfYearNotProdTimes = 0d;
            for (int l = 0; l < 12; l += 3) {
                IntacQuotaDetVo item = new IntacQuotaDetVo();
                item.setStandTimes(monthItems.get(l).getStandTimes() + monthItems.get(l + 1).getStandTimes() + monthItems.get(l + 2).getStandTimes());
                item.setAllProdTimes(monthItems.get(l).getAllProdTimes() + monthItems.get(l + 1).getAllProdTimes() + monthItems.get(l + 2).getAllProdTimes());
                item.setAllProdTimes(Math.round(item.getAllProdTimes() * 100) / 100d);
                item.setNotProdTimes(monthItems.get(l).getNotProdTimes() + monthItems.get(l + 1).getNotProdTimes() + monthItems.get(l + 2).getNotProdTimes());
                item.setNotProdTimes(Math.round(item.getNotProdTimes() * 100) / 100d);
                if (item.getStandTimes() - item.getNotProdTimes() == 0) {
                    item.setIntactRate(BigDecimal.ZERO);
                } else {
                    Double intactRate = (item.getStandTimes() - item.getAllProdTimes()) / (item.getStandTimes() - item.getNotProdTimes());
                    BigDecimal ratio = BigDecimal.valueOf(intactRate).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                    item.setIntactRate(ratio);
                }
                quarterItems.add(item);
                yearStanTimes += item.getStandTimes();
                yearAllProdTimes += item.getAllProdTimes();
                yearNotProdTimes += item.getNotProdTimes();
                if(l < 6){
                    halfYearStanTimes += item.getStandTimes();
                    halfYearAllProdTimes += item.getAllProdTimes();
                    halfYearNotProdTimes += item.getNotProdTimes();
                }
            }
            vo.setQuarterItems(quarterItems);
            // 累计上半年
            halfYearItems.setStandTimes(halfYearStanTimes);
            halfYearItems.setAllProdTimes(Math.round(halfYearAllProdTimes * 100) / 100d);
            halfYearItems.setNotProdTimes(Math.round(halfYearNotProdTimes * 100) / 100d);
            if (halfYearItems.getStandTimes() - halfYearItems.getNotProdTimes() == 0) {
                halfYearItems.setIntactRate(BigDecimal.ZERO);
            } else {
                Double intactRate = (halfYearItems.getStandTimes() - halfYearItems.getAllProdTimes()) / (halfYearItems.getStandTimes() - halfYearItems.getNotProdTimes());
                BigDecimal ratio = BigDecimal.valueOf(intactRate).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                halfYearItems.setIntactRate(ratio);
            }
            vo.setHalfYearItems(halfYearItems);
            // 累计全年
            yearItems.setStandTimes(yearStanTimes);
            yearItems.setAllProdTimes(Math.round(yearAllProdTimes * 100) / 100d);
            yearItems.setNotProdTimes(Math.round(yearNotProdTimes * 100) / 100d);
            if (yearItems.getStandTimes() - yearItems.getNotProdTimes() == 0) {
                yearItems.setIntactRate(BigDecimal.ZERO);
            } else {
                Double intactRate = (yearItems.getStandTimes() - yearItems.getAllProdTimes()) / (yearItems.getStandTimes() - yearItems.getNotProdTimes());
                BigDecimal ratio = BigDecimal.valueOf(intactRate).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                yearItems.setIntactRate(ratio);
            }
            vo.setYearItems(yearItems);

            managevo.add(vo);
        }

        List<IntactRatioVo> vo = new ArrayList<>();
        for (String s : depts) {
            IntactRatioVo intactRatioVo = new IntactRatioVo();
            intactRatioVo.setDeptId(s);
            intactRatioVo.setDeptName(deptmap.get(s));
            List<String> manageIds = manageDept.get(s);
            List<IntactRatioVo> manageRatio = managevo.stream().filter(m -> manageIds.contains(m.getDeptId())).collect(Collectors.toList());
            // 单位级赋值
            intactRatioVo.setUnitDet(manageRatio);

            // 部门级月份
            statisticsDepRate(intactRatioVo, manageRatio);
//            List<IntacQuotaDetVo> deptMonthVo = new ArrayList<>();
//            for (int i = 0; i < 12; i++) {
//                IntacQuotaDetVo intacQuotaDetVo = new IntacQuotaDetVo();
//            }


            vo.add(intactRatioVo);
        }
        IntactRatioVo intactRatioVo = new IntactRatioVo();
        intactRatioVo.setDeptName("公司合计");
        statisticsDepRate(intactRatioVo, vo);
        vo.add(intactRatioVo);

        return vo;
    }

    /**
     * 匹配时间范围内的机组记录
     *
     * @param startDate
     * @param endDate
     * @param unitAllRelist
     * @return
     */
    private List<EquipmentHistoryBean> getUniRecordList(Date startDate, Date endDate, List<EquipmentHistoryBean> unitAllRelist) {
        List<EquipmentHistoryBean> list = new ArrayList<>();
        if (CollUtil.isEmpty(unitAllRelist)) {
            return list;
        }
        for (EquipmentHistoryBean d : unitAllRelist) {
            if (d.getChangeTime().getTime() >= startDate.getTime() && d.getChangeTime().getTime() <= endDate.getTime()) {
                list.add(d);
            }
        }
        return list;
    }


    private static final double convertTime = 1000 * 60 * 60d;

    /**
     * 计算时长
     *
     * @param type           统计类型
     * @param latelyRecord   机组最后记录
     * @param curDate        当前时间
     * @param startDate      开始统计时间
     * @param endDate        结束统计时间
     * @param unitRecordList 机组记录
     * @return
     */
    private double getUnitDisableTime(String type, EquipmentHistoryBean latelyRecord, Date curDate, Date startDate, Date endDate, List<EquipmentHistoryBean> unitRecordList) {

        double disabledTime = 0d;
        //机组当月所有记录为空
        if (CollUtil.isEmpty(unitRecordList)) {
            //当前月没有记录， 需要查找最近的一条记录
            if (latelyRecord != null) {
                if (IntactRatioUntil.isDisableUnitRecord(latelyRecord.getAfterStatus(), type)) {
                    //true 不可用
                    double l = (curDate.getTime() - startDate.getTime()) / convertTime;
                    disabledTime += l;
                    return disabledTime;
                }
            }
            return 0d;
        } else {
            Stack<EquipmentHistoryBean> stack = new Stack<>();

            for (int i = 0; i < unitRecordList.size(); i++) {
                if (IntactRatioUntil.isDisableUnitRecord(unitRecordList.get(i).getAfterStatus(), type)) {
                    stack.push(unitRecordList.get(i));
                }

                //第一条记录要用月初时间计算
                if (i == 0) {
                    if (IntactRatioUntil.isDisableUnitRecord(unitRecordList.get(i).getBeforeStatus(), type)) {
                        double l = (unitRecordList.get(i).getChangeTime().getTime() - startDate.getTime()) / convertTime;
                        disabledTime += l;
                    }
                } else {
                    if (IntactRatioUntil.isDisableUnitRecord(unitRecordList.get(i).getBeforeStatus(), type)) {
                        if (stack.size() == 1) {
                            if (i + 1 < unitRecordList.size()) {
                                EquipmentHistoryBean nextDto = unitRecordList.get(i + 1);
                                if (nextDto != null && IntactRatioUntil.isDisableUnitRecord(nextDto.getBeforeStatus(), type)) {
                                    continue;
                                }
                            }
                            EquipmentHistoryBean pop = stack.pop();
                            double l = (unitRecordList.get(i).getChangeTime().getTime() - pop.getChangeTime().getTime()) / convertTime;
                            disabledTime += l;
                        } else {
                            if (stack.size() > 0) {
                                EquipmentHistoryBean pop = stack.pop();
                            }
                        }
                    }
                }
                //最后一条记录 要用月尾时间计算
                if ((i + 1) == unitRecordList.size()) {
                    if (IntactRatioUntil.isDisableUnitRecord(unitRecordList.get(i).getAfterStatus(), type)) {
                        EquipmentHistoryBean firstStack = getFirstStack(stack);
                        if (firstStack != null) {
                            double l = (endDate.getTime() - firstStack.getChangeTime().getTime()) / convertTime;
                            disabledTime += l;
                        } else {
                            double l = (endDate.getTime() - unitRecordList.get(i).getChangeTime().getTime()) / convertTime;
                            disabledTime += l;
                        }
                    }
                }
            }
        }
        return disabledTime;
    }

    /**
     * 栈-顶级记录
     *
     * @param stack
     * @return
     */
    private EquipmentHistoryBean getFirstStack(Stack<EquipmentHistoryBean> stack) {
        while (stack.size() > 0) {
            if (stack.size() == 1) {
                return stack.pop();
            } else {
                stack.pop();
            }
        }
        return null;
    }


    /**
     * 计算部级
     *
     * @param vo
     * @param list
     */
    private void statisticsDepRate(IntactRatioVo vo, List<IntactRatioVo> list) {
        if (CollUtil.isEmpty(list)) {
            list = new ArrayList<>();
        }
        Integer count = 0;
        List<IntacQuotaDetVo> monthItems = new ArrayList<>();
        List<IntacQuotaDetVo> quarterItems = new ArrayList<>();
        // 上半年
        IntacQuotaDetVo halfYearItems = new IntacQuotaDetVo();
        // 全年
        IntacQuotaDetVo yearItems = new IntacQuotaDetVo();

        yearItems.setStandTimes(0d);
        yearItems.setAllProdTimes(0d);
        yearItems.setNotProdTimes(0d);

        halfYearItems.setStandTimes(0d);
        halfYearItems.setAllProdTimes(0d);
        halfYearItems.setNotProdTimes(0d);

        initItems(monthItems, 12);
        initItems(quarterItems, 4);
        for (int i = 0; i < list.size(); i++) {
            count += list.get(i).getCount();
            List<IntacQuotaDetVo> tempMonthItems = list.get(i).getMonthItems();
            for (int j = 0; j < tempMonthItems.size(); j++) {
                monthItems.get(j).setStandTimes(monthItems.get(j).getStandTimes() + tempMonthItems.get(j).getStandTimes());
                monthItems.get(j).setAllProdTimes(monthItems.get(j).getAllProdTimes() + tempMonthItems.get(j).getAllProdTimes());
                monthItems.get(j).setAllProdTimes(Math.round(monthItems.get(j).getAllProdTimes() * 100) / 100d);
                monthItems.get(j).setNotProdTimes(monthItems.get(j).getNotProdTimes() + tempMonthItems.get(j).getNotProdTimes());
                monthItems.get(j).setNotProdTimes(Math.round(monthItems.get(j).getNotProdTimes() * 100) / 100d);

                if (j < 6) {
                    halfYearItems.setStandTimes(halfYearItems.getStandTimes() + tempMonthItems.get(j).getStandTimes());
                    halfYearItems.setAllProdTimes(halfYearItems.getAllProdTimes() + tempMonthItems.get(j).getAllProdTimes());
                    halfYearItems.setAllProdTimes(Math.round(halfYearItems.getAllProdTimes() * 100) / 100d);
                    halfYearItems.setNotProdTimes(halfYearItems.getNotProdTimes() + tempMonthItems.get(j).getNotProdTimes());
                    halfYearItems.setNotProdTimes(Math.round(halfYearItems.getNotProdTimes() * 100) / 100d);
                }

                yearItems.setStandTimes(yearItems.getStandTimes() + tempMonthItems.get(j).getStandTimes());
                yearItems.setAllProdTimes(yearItems.getAllProdTimes() + tempMonthItems.get(j).getAllProdTimes());
                yearItems.setAllProdTimes(Math.round(yearItems.getAllProdTimes() * 100) / 100d);
                yearItems.setNotProdTimes(yearItems.getNotProdTimes() + tempMonthItems.get(j).getNotProdTimes());
                yearItems.setNotProdTimes(Math.round(yearItems.getNotProdTimes() * 100) / 100d);

                if (monthItems.get(j).getStandTimes() - monthItems.get(j).getNotProdTimes() == 0) {
//                    monthItems.get(j).setIntactRate(BigDecimal.ZERO);
                    monthItems.get(j).setIntactRate(BigDecimal.valueOf(100l));
                } else {
                    Double intactRate = (monthItems.get(j).getStandTimes() - monthItems.get(j).getAllProdTimes()) / (monthItems.get(j).getStandTimes() - monthItems.get(j).getNotProdTimes());
                    BigDecimal ratio = BigDecimal.valueOf(intactRate).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                    monthItems.get(j).setIntactRate(ratio);
                }
            }
        }
        vo.setCount(count);
        for (int h = 0; h < 4; h++) {
            quarterItems.get(h).setStandTimes(monthItems.get(h * 3).getStandTimes() + monthItems.get(h * 3 + 1).getStandTimes() + monthItems.get(h * 3 + 2).getStandTimes());
            quarterItems.get(h).setAllProdTimes(monthItems.get(h * 3).getAllProdTimes() + monthItems.get(h * 3 + 1).getAllProdTimes() + monthItems.get(h * 3 + 2).getAllProdTimes());
            quarterItems.get(h).setAllProdTimes(Math.round(quarterItems.get(h).getAllProdTimes() * 100) / 100d);
            quarterItems.get(h).setNotProdTimes(monthItems.get(h * 3).getNotProdTimes() + monthItems.get(h * 3 + 1).getNotProdTimes() + monthItems.get(h * 3 + 2).getNotProdTimes());
            quarterItems.get(h).setNotProdTimes(Math.round(quarterItems.get(h).getNotProdTimes() * 100) / 100d);
            if (quarterItems.get(h).getStandTimes() - quarterItems.get(h).getNotProdTimes() == 0) {
                quarterItems.get(h).setIntactRate(BigDecimal.ZERO);
            } else {
                Double intactRate = (quarterItems.get(h).getStandTimes() - quarterItems.get(h).getAllProdTimes()) / (quarterItems.get(h).getStandTimes() - quarterItems.get(h).getNotProdTimes());
                BigDecimal ratio = BigDecimal.valueOf(intactRate).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                quarterItems.get(h).setIntactRate(ratio);
            }
        }
        vo.setMonthItems(monthItems);
        vo.setQuarterItems(quarterItems);
        // 上半年
        if (halfYearItems.getStandTimes() - halfYearItems.getNotProdTimes() == 0) {
            halfYearItems.setIntactRate(BigDecimal.ZERO);
        } else {
            Double intactRate = (halfYearItems.getStandTimes() - halfYearItems.getAllProdTimes()) / (halfYearItems.getStandTimes() - halfYearItems.getNotProdTimes());
            BigDecimal ratio = BigDecimal.valueOf(intactRate).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
            halfYearItems.setIntactRate(ratio);
        }
        vo.setHalfYearItems(halfYearItems);

        // 全年
        if (yearItems.getStandTimes() - yearItems.getNotProdTimes() == 0) {
            yearItems.setIntactRate(BigDecimal.ZERO);
        } else {
            Double intactRate = (yearItems.getStandTimes() - yearItems.getAllProdTimes()) / (yearItems.getStandTimes() - yearItems.getNotProdTimes());
            BigDecimal ratio = BigDecimal.valueOf(intactRate).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
            yearItems.setIntactRate(ratio);
        }
        vo.setYearItems(yearItems);
        return;
    }

    private void initItems(List<IntacQuotaDetVo> items, Integer index) {
        for (int i = 0; i < index; i++) {
            IntacQuotaDetVo dto = new IntacQuotaDetVo();
            dto.setIntactRate(BigDecimal.valueOf(100));
            dto.setStandTimes(0d);
            dto.setAllProdTimes(0d);
            dto.setNotProdTimes(0d);
            items.add(dto);
        }
    }


    /**
     * 机组运行台时
     *
     * @param factory
     * @param beginDay
     * @param endDay
     * @return
     */
    @TaskAnnotation("unitRunTime")
    public List<UnitRunTimeVo> unitRunTime(SessionFactory factory, Date beginDay, Date endDay) {
        EquipmentDto equipmentDto = new EquipmentDto("UNIT");
        StartLogBeanMapper mapper = factory.getMapper(StartLogBeanMapper.class);
        List<EquipmentBean> unitlist = factory.getMapper(EquipmentDeMapper.class).queryList(equipmentDto);//所有机组

        if (CollUtil.isEmpty(unitlist)) {
            return new ArrayList<>();
        }

        List<StartLogBean> allUnitlog = mapper.queryByOperateTimeBetweenEqualAndEquipmentId(beginDay, endDay);//机组区间内所有开关机日志

        List<UnitHourVo> unithourvolist = new ArrayList();
        // 遍历机组
        for (EquipmentBean unit : unitlist) {
            UnitHourVo unitHourVo = new UnitHourVo(unit.getDeptManage(), unit.getId(), unit.getEquipmentName());
            unitHourVo.setSimpleName(IntactRatioUntil.getSimpleName(unit.getEquipmentName()));
            long time = 0L;

            List<StartLogBean> unitloglist = allUnitlog.stream().filter(u -> u.getEquipmentId().equals(unit.getEquipmentId())).collect(Collectors.toList());
//            List<StartLogBean> unitloglist = mapper.queryByOperateTimeBetweenEqualAndEquipmentId(beginDay, endDay, unit.getEquipmentId());//机组区间内所有开关机日志
            long nowtime = new Date().getTime();
            if (CollUtil.isEmpty(unitloglist)) {
                // 查询时间段内没有开停机日志，可能一直开机也可能一直停机
                // 查询结束时间后、最近的一次开停机日志，机组状态就是日志的开停机状态反向
                StartLogBean nextLog = mapper.queryByEquipmentIdAndOperateTimeAfter(unit.getId(), endDay);
                if (nextLog != null && !"START_UP".equals(nextLog.getOperateType())) {// 不是开机操作，就是停机操作
                    time = endDay.getTime() - beginDay.getTime();
                } else if (nextLog == null) {
                    // 查询开始时间前、最近的一次开停机日志，机组状态就是日志的开停机h状态
                    StartLogBean preLog = mapper.queryByEquipmentIdAndOperateTimeBefore(unit.getEquipmentId(), beginDay);
                    if (preLog != null && "START_UP".equals(preLog.getOperateType())) {// 最近一次操作是开机，说明一直是开机
                        // 如果结束时间 大于 当前时间，用当前时间去减
                        if(endDay.getTime() > nowtime){
                            time = nowtime - beginDay.getTime();
                        } else {
                            // 小于 用结束时间减
                            time = endDay.getTime() - beginDay.getTime();
                        }
                    }
                }
            } else if (unitloglist.size() == 1) {
                StartLogBean unitlog = unitloglist.get(0);
                if ("START_UP".equals(unitlog.getOperateType())) {
                    // 如果结束时间 大于 当前时间，用当前时间去减
                    if(endDay.getTime() > nowtime){
                        time = nowtime - unitlog.getOperateTime().getTime();
                    } else {
                        // 小于 用结束时间减
                        time = endDay.getTime() - unitlog.getOperateTime().getTime();
                    }
                } else {
                    time = unitlog.getOperateTime().getTime() - beginDay.getTime();
                }
            } else {
                // 按照开停机操作时间从小到大排序，判断第一条和最后一条日志的开停机状态
                // 停机时间 - 开机时间 = 运行时间，多个运行时间总和 + 前后两端的开机时间(如果有) = 运行台时
                StartLogBean firstLog = unitloglist.get(0);
                StartLogBean lastLog = unitloglist.get(unitloglist.size() - 1);
                if ("START_UP".equals(firstLog.getOperateType()) && !"START_UP".equals(lastLog.getOperateType())) {
                    // 前开后停
                    for (int i = 0; i < unitloglist.size(); i++) {
                        //不是开机成功不纳入计算
                        if (!unitloglist.get(i).getOperateType().equals(StartLogEnum.START_UP.getStr())) {
                            continue;
                        }
                        if (unitloglist.size() - 1 == i) {
                            break;
                        }
                        Date startTime = unitloglist.get(i).getOperateTime();
                        Date endTime = unitloglist.get(i + 1).getOperateTime();
                        long interval = endTime.getTime() - startTime.getTime();
                        time += interval;
                    }
                } else if ("START_UP".equals(firstLog.getOperateType()) && "START_UP".equals(lastLog.getOperateType())) {
                    // 前开后开
                    for (int i = 0; i < unitloglist.size(); i++) {
                        //不是开机成功不纳入计算
                        if (!unitloglist.get(i).getOperateType().equals(StartLogEnum.START_UP.getStr())) {
                            continue;
                        }
                        if (unitloglist.size() - 1 == i) {
                            break;
                        }
                        long interval = unitloglist.get(i + 1).getOperateTime().getTime() - unitloglist.get(i).getOperateTime().getTime();
                        time += interval;
                    }
                    long temp = 0;
                    // 如果结束时间 大于 当前时间，用当前时间去减
                    if(endDay.getTime() > nowtime){
                        temp = nowtime - lastLog.getOperateTime().getTime();
                    } else {
                        // 小于 用结束时间减
                        temp = endDay.getTime() - lastLog.getOperateTime().getTime();
                    }
                    time += temp;
                } else if (!"START_UP".equals(firstLog.getOperateType()) && "START_UP".equals(lastLog.getOperateType())) {
                    // 前停后开
                    for (int i = 1; i < unitloglist.size(); i++) {
                        //不是开机成功不纳入计算
                        if (!unitloglist.get(i).getOperateType().equals(StartLogEnum.START_UP.getStr())) {
                            continue;
                        }
                        if (unitloglist.size() - 1 == i) {
                            break;
                        }
                        long interval = unitloglist.get(i + 1).getOperateTime().getTime() - unitloglist.get(i).getOperateTime().getTime();
                        time += interval;
                    }
                    long temp1 = firstLog.getOperateTime().getTime() - beginDay.getTime();
                    time += temp1;
                    long temp2 = endDay.getTime() - lastLog.getOperateTime().getTime();
                    // 如果结束时间 大于 当前时间，用当前时间去减
                    if(endDay.getTime() > nowtime){
                        temp2 = nowtime - lastLog.getOperateTime().getTime();
                    } else {
                        // 小于 用结束时间减
                        temp2 = endDay.getTime() - lastLog.getOperateTime().getTime();
                    }
                    time += temp2;
                } else {
                    // 前停后停
                    for (int i = 1; i < unitloglist.size(); i++) {
                        //不是开机成功不纳入计算
                        if (!unitloglist.get(i).getOperateType().equals(StartLogEnum.START_UP.getStr())) {
                            continue;
                        }
                        if (unitloglist.size() - 1 == i) {
                            break;
                        }
                        long interval = unitloglist.get(i + 1).getOperateTime().getTime() - unitloglist.get(i).getOperateTime().getTime();
                        time += interval;
                    }
                    long temp = firstLog.getOperateTime().getTime() - beginDay.getTime();
                    time += temp;
                }
            }
//            long hour = Convert.convertTime(time, TimeUnit.MILLISECONDS, TimeUnit.HOURS);
            double hour = IntactRatioUntil.longtimeToHour(time);
            unitHourVo.setMachineHour(hour);
            unithourvolist.add(unitHourVo);
        }
        //所有单位
        List<UnitRunTimeVo> deptManagelist = unitlist.stream().map(u -> {
            return new UnitRunTimeVo(u.getDeptManage(), u.getDeptManageName());
        }).distinct().collect(Collectors.toList());

        deptManagelist.stream().forEach(d -> {
            List<UnitHourVo> det = unithourvolist.stream().filter(u -> u.getDeptManage().equals(d.getDeptManage())).collect(Collectors.toList());
            double sum = det.stream().mapToDouble(UnitHourVo::getMachineHour).sum();
            UnitHourVo unitHourVo = new UnitHourVo(d.getDeptManage(), null, "合计");
            unitHourVo.setMachineHour(BigDecimal.valueOf(sum).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
            det.add(unitHourVo);
            d.setDet(det);
        });
        return deptManagelist;
    }


    /**
     * 机组检修台时
     *
     * @param factory
     * @param beginDay
     * @param endDay
     * @return
     */
    @TaskAnnotation("unitOverhaulTime")
    public List<OverhaulTimeVo> unitOverhaulTime(SessionFactory factory, Date beginDay, Date endDay) {
        long time = endDay.getTime();
        time = time + 24 * 60 * 60 * 1000 - 1;
        endDay = DateUtil.date(time);//结束时间取到当天最后
        EquipmentDeMapper mapper = factory.getMapper(EquipmentDeMapper.class);
        EquipmentHistoryMapper historymapper = factory.getMapper(EquipmentHistoryMapper.class);

        //所有机组
        List<EquipmentBean> allunitlist = mapper.queryList(new EquipmentDto("UNIT"));

        //所有部门
        List<String> deptlist = allunitlist.stream().map(EquipmentBean::getDeptId).distinct().collect(Collectors.toList());
        Map<String, String> deptmap = allunitlist.stream().collect(Collectors.toMap(EquipmentBean::getDeptId, EquipmentBean::getDeptName, (v1, v2) -> v1));

        //部门对应的机组数量
        Map<String, List<EquipmentBean>> deptUnitsmap = allunitlist.stream().collect(Collectors.groupingBy(EquipmentBean::getDeptId));

        //所有单位
        Map<String, String> deptmange = allunitlist.stream().collect(Collectors.toMap(EquipmentBean::getDeptManage, EquipmentBean::getDeptManageName, (v1, v2) -> v1));

        //部门下的单位
        Map<String, List<String>> manageDept = new HashMap<>();
        for (String s : deptmap.keySet()) {
            List<String> manage = allunitlist.stream().filter(u -> u.getDeptId().equals(s)).map(EquipmentBean::getDeptManage).distinct().collect(Collectors.toList());
            manageDept.put(s, manage);
        }

        //机组条件范围所有记录
        List<EquipmentHistoryBean> historylist = historymapper.queryAllByChangeTimeBetweenAndEquipmentType(beginDay, endDay, EquipmentEnum.UNIT.getValue());

        //机组条件范围内最新的操作记录
        List<EquipmentHistoryBean> lastHistorylist = historymapper.queryStatusListByMaxChangeTime(endDay, EquipmentEnum.UNIT.getValue());
        Map<String, EquipmentHistoryBean> lastHistorymap = new HashMap<>();
        for (EquipmentHistoryBean bean : lastHistorylist) {
            lastHistorymap.put(bean.getEquipmentId(), bean);
        }


        List<OverhaulDetVo> detVolist = new ArrayList<>();
        // 遍历单位
        for (EquipmentBean unit : allunitlist) {
            OverhaulDetVo overhaulDetVo = new OverhaulDetVo(unit.getDeptManage(), unit.getEquipmentId(), unit.getEquipmentName());
            long l = DateUtil.betweenDay(beginDay, endDay, true) + 1;
            overhaulDetVo.setH0((double) (l * 24));//标准总台时数

            // 单个机组条件范围内记录
            List<EquipmentHistoryBean> unitRecordlist = historylist.stream().filter(h -> h.getEquipmentId().equals(unit.getEquipmentId())).collect(Collectors.toList());

            // 检修台时-故障检修时间(H1)
            Double repairHourH1 = getUnitOverhaulTime(lastHistorymap.get(unit.getEquipmentId()), OverhaulStatusEnum.TROUBLESHOOTING.getValue(), beginDay, endDay, unitRecordlist);
            // 检修台时-计划检修时间(H2)
            Double repairHourH2 = getUnitOverhaulTime(lastHistorymap.get(unit.getEquipmentId()), OverhaulStatusEnum.planned.getValue(), beginDay, endDay, unitRecordlist);
            // 检修台时-正常维护时间(H3)
            Double repairHourH3 = getUnitOverhaulTime(lastHistorymap.get(unit.getEquipmentId()), OverhaulStatusEnum.normal.getValue(), beginDay, endDay, unitRecordlist);
            // 检修台时-大修时间(H4)
            Double repairHourH4 = getUnitOverhaulTime(lastHistorymap.get(unit.getEquipmentId()), OverhaulStatusEnum.OVERHAUL.getValue(), beginDay, endDay, unitRecordlist);
            // 检修台时-总检修时间(H5)
            Double repairHourH5 = repairHourH1 + repairHourH2 + repairHourH3 + repairHourH4;

            overhaulDetVo.setH1(repairHourH1);
            overhaulDetVo.setH2(repairHourH2);
            overhaulDetVo.setH3(repairHourH3);
            overhaulDetVo.setH4(repairHourH4);
            overhaulDetVo.setH5(Math.round(repairHourH5 * 100) / 100d);
            detVolist.add(overhaulDetVo);
        }


        // 部门vo
        List<OverhaulTimeVo> volist = new ArrayList();
        // 遍历部门
        for (String detptId : deptlist) {
            OverhaulTimeVo overhaulTimeVo = new OverhaulTimeVo(detptId, deptmap.get(detptId));
            overhaulTimeVo.setQty(deptUnitsmap.get(detptId).size());
            double h0 = 0d;
            double h1 = 0d;
            double h2 = 0d;
            double h3 = 0d;
            double h4 = 0d;
            double h5 = 0d;
            // 部门下的单位
            List<String> mangelist = manageDept.get(detptId);

            List<List<OverhaulDetVo>> det = new ArrayList<>();
            //单位vo
            List<OverhaulMangeDetVo> mangeDetVo = new ArrayList<>();
            //遍历单位
            for (String mange : mangelist) {
                OverhaulMangeDetVo mangedet = new OverhaulMangeDetVo(mange, deptmange.get(mange));
                OverhaulDetVo unitTotal = new OverhaulDetVo();
                unitTotal.setDeptManage(mange);
                unitTotal.setEquipmentName(StrUtil.format("{}-{}", deptmange.get(mange), "合计"));
                List<OverhaulDetVo> collect = detVolist.stream().filter(d -> d.getDeptManage().equals(mange)).collect(Collectors.toList());
                //单位累计
                double unith0 = collect.stream().mapToDouble(OverhaulDetVo::getH0).sum();
                double unith1 = collect.stream().mapToDouble(OverhaulDetVo::getH1).sum();
                double unith2 = collect.stream().mapToDouble(OverhaulDetVo::getH2).sum();
                double unith3 = collect.stream().mapToDouble(OverhaulDetVo::getH3).sum();
                double unith4 = collect.stream().mapToDouble(OverhaulDetVo::getH4).sum();
                double unith5 = collect.stream().mapToDouble(OverhaulDetVo::getH5).sum();
                unitTotal.setH0(BigDecimal.valueOf(unith0).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
                unitTotal.setH1(BigDecimal.valueOf(unith1).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
                unitTotal.setH2(BigDecimal.valueOf(unith2).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
                unitTotal.setH3(BigDecimal.valueOf(unith3).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
                unitTotal.setH4(BigDecimal.valueOf(unith4).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
                unitTotal.setH5(BigDecimal.valueOf(unith5).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
                collect.add(unitTotal);
                mangedet.setDet(collect);
                mangeDetVo.add(mangedet);
                //部门累计
                h0 = h0 + unith0;
                h1 = h1 + unith1;
                h2 = h2 + unith2;
                h3 = h3 + unith3;
                h4 = h4 + unith4;
                h5 = h5 + unith5;
            }
            overhaulTimeVo.setH0(BigDecimal.valueOf(h0).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
            overhaulTimeVo.setH1(BigDecimal.valueOf(h1).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
            overhaulTimeVo.setH2(BigDecimal.valueOf(h2).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
            overhaulTimeVo.setH3(BigDecimal.valueOf(h3).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
            overhaulTimeVo.setH4(BigDecimal.valueOf(h4).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
            overhaulTimeVo.setH5(BigDecimal.valueOf(h5).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
            overhaulTimeVo.setDet(mangeDetVo);
            volist.add(overhaulTimeVo);
        }
        OverhaulTimeVo overhaulTimeVo = new OverhaulTimeVo("", "公司合计");
        overhaulTimeVo.setQty(allunitlist.size());
        overhaulTimeVo.setH0(volist.stream().mapToDouble(OverhaulTimeVo::getH0).sum());
        overhaulTimeVo.setH1(volist.stream().mapToDouble(OverhaulTimeVo::getH1).sum());
        overhaulTimeVo.setH2(volist.stream().mapToDouble(OverhaulTimeVo::getH2).sum());
        overhaulTimeVo.setH3(volist.stream().mapToDouble(OverhaulTimeVo::getH3).sum());
        overhaulTimeVo.setH4(volist.stream().mapToDouble(OverhaulTimeVo::getH4).sum());
        overhaulTimeVo.setH5(volist.stream().mapToDouble(OverhaulTimeVo::getH5).sum());
        volist.add(overhaulTimeVo);
        return volist;
    }

    /**
     * 累计检修台时
     *
     * @param latelyRecord 条件时间内最新一条记录
     * @param status       检修类型
     *                     OVERHAUL(3),//大修
     *                     TROUBLESHOOTING(4),//故障检修
     *                     planned(5),//计划检修
     *                     normal(6),//正常维护
     * @param startDate    开始时间
     * @param endDate      结束时间
     * @param unitList     机组操作记录
     * @return
     */
    private double getUnitOverhaulTime(EquipmentHistoryBean latelyRecord, int status, Date startDate, Date endDate, List<EquipmentHistoryBean> unitList) {
        // 如果当前时间比较查询条件时候大，把当下时间赋值给结束时间
        if (endDate.getTime()>new Date().getTime()) {
            endDate = new Date();
        }
        double disabledTime = 0d;
        try {
            if (unitList == null || unitList.size() == 0) {
                if (latelyRecord != null) {
                    if (status == latelyRecord.getAfterStatus()) {
                        //true 不可用
                        double l = (endDate.getTime() - startDate.getTime()) / convertTime;
                        disabledTime += l;
                    }
                }
            } else {
                Stack<EquipmentHistoryBean> stack = new Stack<>();

                for (int i = 0; i < unitList.size(); i++) {
                    if (status == unitList.get(i).getAfterStatus()) {
                        stack.push(unitList.get(i));
                    }
                    //第一条记录要用月初时间计算
                    if (i == 0) {
                        if (status == unitList.get(i).getBeforeStatus()) {
                            double l = (unitList.get(i).getChangeTime().getTime() - startDate.getTime()) / convertTime;
                            disabledTime += l;
                        }
                    } else {
                        if (status == unitList.get(i).getBeforeStatus()) {
                            if (stack.size() == 1) {
                                if (i + 1 < unitList.size()) {
                                    EquipmentHistoryBean nextDto = unitList.get(i + 1);
                                    if (nextDto != null && status == nextDto.getBeforeStatus()) {
                                        continue;
                                    }
                                }
                                EquipmentHistoryBean pop = stack.pop();
                                double l = (unitList.get(i).getChangeTime().getTime() - pop.getChangeTime().getTime()) / convertTime;
                                disabledTime += l;
                            } else {
                                if (stack.size() > 0) {
                                    EquipmentHistoryBean pop = stack.pop();
                                }
                            }
                        }
                    }
                    //最后一条记录 要用月尾时间计算
                    if ((i + 1) == unitList.size()) {
                        if (status == unitList.get(i).getAfterStatus()) {
                            EquipmentHistoryBean firstStack = getFirstStack(stack);
                            if (firstStack != null) {
                                double l = (endDate.getTime() - firstStack.getChangeTime().getTime()) / convertTime;
                                disabledTime += l;
                            } else {
                                double l = (endDate.getTime() - unitList.get(i).getChangeTime().getTime()) / convertTime;
                                disabledTime += l;
                            }

                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
        return Math.round(disabledTime * 100) / 100d;
    }
}
